package com.denlaku.longan.service.impl;

import com.denlaku.longan.config.LonganProperties;
import com.denlaku.longan.index.IndexComponent;
import com.denlaku.longan.service.DictionaryService;
import com.denlaku.longan.service.IndexComponentService;
import com.denlaku.longan.vo.LexiconItem;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.ControlledRealTimeReopenThread;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.SearcherManager;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.lionsoul.jcseg.ISegment;
import org.lionsoul.jcseg.analyzer.JcsegAnalyzer;
import org.lionsoul.jcseg.dic.ADictionary;
import org.lionsoul.jcseg.segmenter.SegmenterConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author tianx
 */
@Service
@Slf4j
public class IndexComponentServiceImpl implements IndexComponentService {
    private static final String INDEX_PATH = "indies";

    private final Map<String, IndexComponent> indexComponentMap = new ConcurrentHashMap<>();

    @Autowired
    private LonganProperties configProperties;

    @Autowired
    private DictionaryService dictionaryService;

    @Override
    public IndexComponent getOrInitIndexComponent(String namespace, String biz, List<LexiconItem> lexiconItems) {
        String cacheKey = String.join("-", namespace, biz);
        IndexComponent indexComponent = indexComponentMap.get(cacheKey);
        if (indexComponent != null) {
            return indexComponent;
        }
        return indexComponentMap.computeIfAbsent(cacheKey, key -> initIndexComponent(namespace, biz, lexiconItems));
    }

    @Override
    public IndexComponent getIndexComponent(String namespace, String biz) {
        String key = String.join("-", namespace, biz);
        return indexComponentMap.get(key);
    }

    @SneakyThrows
    private IndexComponent initIndexComponent(String namespace, String biz, List<LexiconItem> lexiconItems) {
        try {
            ADictionary defaultDictionary = dictionaryService.getOrInitDictionary(namespace);
            SegmenterConfig segmenterConfig = defaultDictionary.getConfig();
            dictionaryService.loadLexiconItems(namespace, lexiconItems);

            //使用标准的分词算法对原始记录表进行拆分
            Analyzer analyzer = new JcsegAnalyzer(ISegment.COMPLEX, segmenterConfig, defaultDictionary);

            //创建IndexWriter对象
            Path path = Paths.get(configProperties.getResourceLocation(), INDEX_PATH, namespace, biz);
            Directory directory = FSDirectory.open(path);

            IndexWriter indexWriter = new IndexWriter(directory, new IndexWriterConfig(analyzer));

            SearcherManager sm = new SearcherManager(indexWriter, true, true, null);

            ControlledRealTimeReopenThread<IndexSearcher> thread
                    = new ControlledRealTimeReopenThread<>(indexWriter, sm, 60, 1);

            thread.setDaemon(true);
            thread.setName(String.join(",", "ControlledRealTimeReopenThread", namespace, biz));
            thread.start();

            IndexComponent indexComponent = new IndexComponent();
            indexComponent.setSearcherManager(sm);
            indexComponent.setIndexWriter(indexWriter);
            indexComponent.setAnalyzer(analyzer);
            indexComponent.setDictionary(defaultDictionary);

            return indexComponent;
        } catch (Exception e) {
            log.error("Failed to init index component", e);
            throw new RuntimeException(e);
        }
    }
}
